package lesson

import (
	"context"
	"database/sql"
	"errors"
	"github.com/gogf/gf/v2/crypto/gmd5"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"server/internal/consts"
	"server/internal/dao"
	"server/internal/model"
	"server/internal/model/do"
	"server/internal/model/entity"
	"server/internal/service"
)

type sLessonUser struct {
}

func init() {
	service.RegisterLessonUser(&sLessonUser{})
}

// Login 用户账号密码登录
func (s *sLessonUser) Login(ctx context.Context, in model.LessonUserLoginInput) (token string, err error) {
	userInfo := new(entity.LessonUser)
	err = dao.LessonUser.Ctx(ctx).Where(do.LessonUser{Phone: in.Phone}).Scan(userInfo)
	if errors.Is(err, sql.ErrNoRows) {
		return "", gerror.New("用户未注册")
	}
	if err != nil {
		return
	}

	//验证密码
	in.Password, err = s.EncryptPassword(in.Password)
	if err != nil {
		return
	}
	if userInfo.Password != in.Password {
		return "", gerror.New("密码错误")
	}

	return s.handleLogin(ctx, userInfo)
}

// EncryptPassword 对用户输入的密码进行md5加密
func (s *sLessonUser) EncryptPassword(password string) (string, error) {
	result, err := gmd5.EncryptString(password)
	if err != nil {
		return "", err
	}
	return result, nil
}

func (s *sLessonUser) handleLogin(ctx context.Context, userInfo *entity.LessonUser) (token string, err error) {
	// 生成token
	token, err = service.Jwt().GenerateToken(ctx, int64(userInfo.Id), userInfo.Name, consts.JwtAudienceApp)

	// 无状态下不需要缓存用户其他信息

	return
}

// Logout 用户退出
func (s *sLessonUser) Logout(ctx context.Context) (err error) {
	// TODO 后期可考虑对已退出的用户token进行限制

	return nil
}

// CheckPhoneRepeat 检测手机号是否重复
func (s *sLessonUser) CheckPhoneRepeat(ctx context.Context, phone string, id int64) (err error) {
	where := g.Map{
		"phone": phone,
	}
	if id > 0 {
		where["id <> ?"] = id
	}
	count, err := dao.LessonUser.Ctx(ctx).Where(where).Count()
	if err != nil {
		return err
	}
	if count > 0 {
		return gerror.New("手机号重复")
	}
	return nil
}

// Register 用户账号密码注册
func (s *sLessonUser) Register(ctx context.Context, in model.LessonUserRegisterInput) (ID int64, err error) {
	if err = s.CheckPhoneRepeat(ctx, in.Phone, 0); err != nil {
		return
	}
	in.Password, err = s.EncryptPassword(in.Password)
	if err != nil {
		return
	}

	// 新用户注册
	ID, err = dao.LessonUser.Ctx(ctx).Data(do.LessonUser{
		Phone:    in.Phone,
		Name:     in.Name,
		Password: in.Password,
	}).InsertAndGetId()
	if err != nil {
		return 0, err
	}

	return ID, nil
}

func (s *sLessonUser) ParseLoginUserID(ctx context.Context) (ID int64, err error) {
	token := g.RequestFromCtx(ctx).Header.Get("X-Token")
	claims, err := service.Jwt().ParseToken(ctx, token)
	if err != nil {
		return 0, err
	}
	if !service.Jwt().ValidateAudience(claims, consts.JwtAudienceApp) {
		return 0, gerror.New("user token audience use error")
	}
	return claims.UserId, nil
}

func (s *sLessonUser) Detail(ctx context.Context, id int64) (userInfo *model.LessonUserDetail, err error) {
	userInfo = new(model.LessonUserDetail)
	err = dao.LessonUser.Ctx(ctx).Where(do.LessonUser{Id: id}).Scan(userInfo)
	return
}

func (s *sLessonUser) List(ctx context.Context, in model.LessonUserListInput) (data []model.LessonUserListItem, total int, err error) {
	data = make([]model.LessonUserListItem, 0)
	err = dao.LessonUser.Ctx(ctx).Page(in.Page, in.PageSize).ScanAndCount(&data, &total, true)
	return
}
